package com.yupi.usercenter.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yupi.usercenter.common.ErrorCode;
import com.yupi.usercenter.exception.BusinessException;
import com.yupi.usercenter.model.DTO.*;
import com.yupi.usercenter.model.Enum.TeamStatusEnum;
import com.yupi.usercenter.model.VO.TeamUserVO;
import com.yupi.usercenter.model.VO.UserVO;
import com.yupi.usercenter.model.domain.Team;
import com.yupi.usercenter.mapper.TeamMapper;
import com.yupi.usercenter.model.domain.User;
import com.yupi.usercenter.model.domain.UserTeam;
import com.yupi.usercenter.service.TeamService;
import com.yupi.usercenter.service.UserService;
import com.yupi.usercenter.service.UserTeamService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

import static com.yupi.usercenter.contant.UserConstant.ADMIN_ROLE;

/**
* @author 20654
* @description 针对表【team(队伍)】的数据库操作Service实现
* @createDate 2025-05-03 20:03:56
*/
@Service
public class TeamServiceImpl extends ServiceImpl<TeamMapper, Team>
    implements TeamService{

    @Resource
    private UserTeamService userTeamService;

    @Autowired
    private UserService userService;

    /**
     * 创建队伍
     * @param team
     * @param loginUser
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public long addTeam(Team team, User loginUser) {
        //1.请求参数是否为空
        if(team == null){
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }

        //2.是否登录，未登录不允许创建
        if(loginUser == null){
            throw new BusinessException(ErrorCode.NOT_LOGIN);
        }

        //3.校验信息,队伍人数是否超出范围
        int maxNum = team.getMaxNum();
        if(maxNum < 1 || maxNum > 20){
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"队伍人数不满足要求");
        }

        //4.队伍标题
        String name = team.getName();
        if(StringUtils.isBlank(name) || name.length() > 20){
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"队伍标题不满足要求");
        }

        //5.队伍描述
        String description = team.getDescription();
        if(StringUtils.isNotBlank(description) && description.length() > 300){
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"队伍描述过长");
        }

        //6.队伍状态
        int status = team.getStatus();
        if(status < 0){
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"队伍状态不满足要求");
        }

        //7.status是否为加密状态
        TeamStatusEnum statusEnum = TeamStatusEnum.getEnumByValue(status);
        if(statusEnum == null){
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"队伍状态不满足要求");
        }
        //如果是加密状态，一定要有密码。且密码小于32位
        if(statusEnum.equals(TeamStatusEnum.SECRET) ) {
            if (StringUtils.isBlank(team.getPassword()) && team.getPassword().length() > 32) {
                throw new BusinessException(ErrorCode.PARAMS_ERROR, "密码设置错误");
            }
        }

        //8.超时时间
        Date expireTime = team.getExpireTime();
        if (expireTime != null) {
            if(new Date().after(expireTime)){
                throw new BusinessException(ErrorCode.PARAMS_ERROR,"超时时间设置错误");
            }
        }

        //9,校验用户创建的队伍数
        //TODO 可能同时有多个线程，所以需要加锁
        QueryWrapper<UserTeam> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("userId",loginUser.getId());
        //查询当前登录用户创建的队伍数量,this代表当前的service
        long hasTeamNum = userTeamService.count(queryWrapper);
        if(hasTeamNum >= 5){
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"用户最多创建5个队伍");
        }

        //10.插入队伍数据
        team.setId(null);
        team.setUserId(loginUser.getId());
        boolean result = this.save(team);
        if (!result){
            throw new BusinessException(ErrorCode.SYSTEM_ERROR,"创建队伍失败");
        }
        //插入到关系表,插入之后mybatis-plus会自动将team的id返回（主键回显）
        Long teamId = team.getId();
        if(teamId == null){
            throw new BusinessException(ErrorCode.SYSTEM_ERROR,"创建队伍失败");
        }
        UserTeam userTeam = new UserTeam();
        userTeam.setUserId(loginUser.getId());
        userTeam.setTeamId(teamId);
        userTeam.setJoinTime(new Date());
        userTeam.setCreateTime(new Date());
        userTeam.setUpdateTime(new Date());
        userTeam.setIsDelete(0);
        boolean result1 = userTeamService.save(userTeam);
        if(!result1){
            throw new BusinessException(ErrorCode.SYSTEM_ERROR,"创建队伍失败");
        }


        return teamId;
    }

    /**
     * 获取列表（包括已加入的队伍）
     * @param teamQuery
     * @param loginUser
     * @return
     */
    @Override
    public List<TeamUserVO> listTeams(TeamQuery teamQuery,User loginUser) {
        if(teamQuery == null){
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        QueryWrapper<Team> queryWrapper = new QueryWrapper<>();
        Long id = teamQuery.getId();
        if(id != null && id > 0){
            queryWrapper.eq("id",id);
        }

        List<Long> idList = teamQuery.getIdList();
        if(idList != null && idList.size() > 0){
            queryWrapper.in("id",idList);
        }

        String searchText = teamQuery.getSearchText();
        if(StringUtils.isNotBlank(searchText)){
            queryWrapper.and(qw -> qw.like("name",searchText).or().like("description",searchText));
        }

        String name = teamQuery.getName();
        if(StringUtils.isNotBlank(name)){
            queryWrapper.like("name",name);
        }

        String description = teamQuery.getDescription();
        if(StringUtils.isNotBlank(description)){
            queryWrapper.like("description",description);
        }

        Integer maxNum = teamQuery.getMaxNum();
        if(maxNum != null && maxNum > 0){
            queryWrapper.eq("maxNum",maxNum);
        }

        Integer status = teamQuery.getStatus();
        //加密房间只有管理员能访问,公开房间可以普通用户访问
        if(status == null ){
            status =0;
        }
        if(status == 1){
            if(loginUser == null || !loginUser.getUserRole().equals(ADMIN_ROLE)){
                throw new BusinessException(ErrorCode.NO_AUTH);
            }
        }
        queryWrapper.eq("status",status);


        Long userId = teamQuery.getUserId();
        if(userId != null && userId > 0){
            queryWrapper.eq("userId",userId);
        }
        queryWrapper.eq("isDelete",0);
        List<Team> teamList = this.list(queryWrapper);
        if (CollectionUtils.isEmpty(teamList)) {
            return new ArrayList<>();
        }

        List<TeamUserVO> teamUserVOList = new ArrayList<>();
        //关联查询创建人的用户信息
        for (Team team : teamList) {
            Long userid = team.getUserId();
            if (userid == null) {
                continue;
            }
            User user = userService.getById(userid);
            TeamUserVO teamUserVO = new TeamUserVO();
            BeanUtils.copyProperties(team,teamUserVO);
            //脱敏用户信息
            UserVO userVO = new UserVO();
            BeanUtils.copyProperties(user,userVO);
            teamUserVO.setCreateUser(userVO);

            //获取当前队伍的人数
            Long teamId = team.getId();
            QueryWrapper<UserTeam> userTeamQueryWrapper = new QueryWrapper<>();
            userTeamQueryWrapper.eq("teamId",teamId);
            teamUserVO.setHasJoinNum(userTeamService.count(userTeamQueryWrapper));
            teamUserVOList.add(teamUserVO);
        }
        extracted(teamUserVOList, loginUser);
        return teamUserVOList;
    }

    /**
     * 更新队伍信息
     * @param teamUpdateDTO
     * @param loginUser
     * @return
     */
    @Override
    public boolean updateTeam(TeamUpdateDTO teamUpdateDTO,User loginUser) {
        if(teamUpdateDTO == null){
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        Long id = teamUpdateDTO.getId();
        if(id == null || id <= 0){
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        Team oldTeam = this.getById(id);
        if(oldTeam == null){
            throw new BusinessException(ErrorCode.NULL_ERROR);
        }
        //只有管理员和创建者可以修改
        if(!oldTeam.getUserId().equals(loginUser.getId()) && !loginUser.getUserRole().equals(ADMIN_ROLE)){
            throw new BusinessException(ErrorCode.NO_AUTH);
        }

        //如果是加密房间，则需要校验密码
        if(oldTeam.getStatus().equals(1)){
            if(StringUtils.isBlank(teamUpdateDTO.getPassword())){
                throw new BusinessException(ErrorCode.PARAMS_ERROR,"加密房间必须输入密码");
            }
        }

        Team updateteam = new Team();
        BeanUtils.copyProperties(teamUpdateDTO,updateteam);
        boolean result = this.updateById(updateteam);

        return result;
    }

    /**
     * 加入队伍
     * @param teamJoinDTO
     * @param loginUser
     * @return
     */
    @Override
    public boolean joinTeam(TeamJoinDTO teamJoinDTO,User loginUser) {
        if(teamJoinDTO == null){
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        Long id =loginUser.getId();
        if(id == null || id <= 0){
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        //判断用户加入了几个队伍
        QueryWrapper<UserTeam> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("userId",id);
        long count = userTeamService.count(queryWrapper);
        if(count >= 5){
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"最多只能加入5个队伍");
        }
        Long teamId = teamJoinDTO.getTeamId();
        if(teamId == null || teamId <= 0){
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }

        Team team = this.getById(teamId);
        if(team == null){
            throw new BusinessException(ErrorCode.NULL_ERROR,"队伍不存在");
        }
        if(team.getStatus().equals(2)){
            if (!teamJoinDTO.getPassword().equals(team.getPassword())) {
                throw new BusinessException(ErrorCode.PARAMS_ERROR,"房间密码错误");
            }
        }

        //检查队伍人数
        if(team.getMaxNum() <= userTeamService.count(new QueryWrapper<UserTeam>().eq("teamId", teamId))){
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"队伍已满");
        }

        //检查用户是否已经加入过这个队伍
        queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("userId",id).eq("teamId",teamId);
        if(userTeamService.count(queryWrapper) > 0){
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"用户已经加入过这个队伍");
        }

        UserTeam userTeam = new UserTeam();
        userTeam.setUserId(loginUser.getId());
        userTeam.setTeamId(teamId);
        userTeam.setJoinTime(new Date());

        boolean save = userTeamService.save(userTeam);

        return save ;
    }

    /**
     * 退出队伍
     * @param teamQuitDTO
     * @param loginUser
     * @return
     */
    @Override
    public boolean quitTeam(TeamQuitDTO teamQuitDTO, User loginUser) {
        if(teamQuitDTO == null){
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        Long teamId = teamQuitDTO.getTeamId();
        if(teamId == null || teamId <= 0){
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        Team team = this.getById(teamId);
        if(team == null){
            throw new BusinessException(ErrorCode.NULL_ERROR);
        }
        long userId = loginUser.getId();
        QueryWrapper<UserTeam> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("teamId",teamId).eq("userId",userId);
        long count = userTeamService.count(queryWrapper);
       if(count <= 0){
           throw new BusinessException(ErrorCode.PARAMS_ERROR,"未加入队伍");
       }

        long teamHasJoinNum = this.countTeamUserByTeamId(teamId);
        //队伍只剩下一个人，解散
        if (teamHasJoinNum == 1) {
            //删除队伍
            this.removeById(teamId);
        } else {
            //队伍至少还剩下两人
            //是队长
            if (team.getUserId() == userId) {
                //把队伍转移给最早加入的用户
                //1.查询已加入队伍的所有用户和加入时间
                QueryWrapper<UserTeam> userTeamQueryWrapper = new QueryWrapper<>();
                userTeamQueryWrapper.eq("teamId", teamId);
                userTeamQueryWrapper.last("order by id asc limit 2");
                List<UserTeam> userTeamList = userTeamService.list(userTeamQueryWrapper);
                if (CollectionUtils.isEmpty(userTeamList) || userTeamList.size() <= 1) {
                    throw new BusinessException(ErrorCode.SYSTEM_ERROR);
                }
                UserTeam nextUserTeam = userTeamList.get(1);
                Long nextTeamLeaderId = nextUserTeam.getUserId();
                //更新当前队伍的队长
                Team updateTeam = new Team();
                updateTeam.setId(teamId);
                updateTeam.setUserId(nextTeamLeaderId);
                boolean result = this.updateById(updateTeam);
                if (!result) {
                    throw new BusinessException(ErrorCode.SYSTEM_ERROR, "更新队伍队长失败");
                }
            }
        }
        //移除关系
        return userTeamService.remove(queryWrapper);
    }

    /**
     * 解散队伍
     * @param id
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean deleteTeam(Long id, User loginUser) {
        //校验队伍是否存在
        Team team = this.getById(id);
        if(team == null){
            throw new BusinessException(ErrorCode.NULL_ERROR,"队伍不存在");
        }

        //队长和管理员才能解散队伍
        if(team.getUserId() != loginUser.getId() && !this.isAdmin(loginUser)){
            throw new BusinessException(ErrorCode.NO_AUTH,"无操作权限");
        }

        //移除所有加入队伍的关联信息
        QueryWrapper<UserTeam> userTeamQueryWrapper = new QueryWrapper<>();
        userTeamQueryWrapper.eq("teamId",id);
        boolean remove = userTeamService.remove(userTeamQueryWrapper);
        if(!remove){
            throw new BusinessException(ErrorCode.SYSTEM_ERROR,"删除队伍失败");
        }

        //删除队伍
        return this.removeById(id);
    }

    @Override
    public TeamUserVO getTeamUserById(Long teamId) {
        //获取队伍信息
        Team team = this.getById(teamId);
        if(team == null){
            throw new BusinessException(ErrorCode.NULL_ERROR,"队伍不存在");
        }
        //根据队伍id来查询队伍信息
        TeamUserVO teamUserVO = baseMapper.getTeamUserById(teamId);
        //查询创建人信息
        User createUser = userService.getById(baseMapper.selectById(teamId).getUserId());
        UserVO createUserVO = new UserVO();
        createUserVO.setId(createUser.getId());
        createUserVO.setUsername(createUser.getUsername());
        createUserVO.setAvatarUrl(createUser.getAvatarUrl());
        teamUserVO.setCreateUser(createUserVO);
        return teamUserVO;
    }

    /**
     * 获取某队伍当前人数
     *
     * @param teamId
     * @return
     */
    private long countTeamUserByTeamId(long teamId) {
        QueryWrapper<UserTeam> userTeamQueryWrapper = new QueryWrapper<>();
        userTeamQueryWrapper.eq("teamId", teamId);
        return userTeamService.count(userTeamQueryWrapper);
    }

    //判断是否为管理员
    private boolean isAdmin(User loginUser){
        return loginUser.getUserRole().equals(ADMIN_ROLE);
    }

    /**
     * 判断用户是否加入了队伍
     * @param teamList
     * @param loginUser
     */
    private void extracted(List<TeamUserVO> teamList, User loginUser) {
        //判断当前用户是否在队伍中
        List<Long> teamIdList = teamList.stream().map(TeamUserVO::getId).collect(Collectors.toList());
        try {
            QueryWrapper<UserTeam> userTeamQueryWrapper = new QueryWrapper<>();
            userTeamQueryWrapper.eq("userId", loginUser.getId());
            userTeamQueryWrapper.in("teamId", teamIdList);
            List<UserTeam> userTeamList = userTeamService.list(userTeamQueryWrapper);
            Set<Long> hasJoinTeamIdList = userTeamList.stream().map(UserTeam::getTeamId).collect(Collectors.toSet());
            for (TeamUserVO teamUserVO : teamList) {
                boolean hasJoin = hasJoinTeamIdList.contains(teamUserVO.getId());
                teamUserVO.setHasJoin(hasJoin);
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}




